package com.xxxx.crm.service;

import com.xxxx.crm.base.BaseService;
import com.xxxx.crm.dao.UserMapper;
import com.xxxx.crm.model.UserModel;
import com.xxxx.crm.utils.AssertUtil;
import com.xxxx.crm.utils.Md5Util;
import com.xxxx.crm.utils.UserIDBase64;
import com.xxxx.crm.vo.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * Created by HMF on 2021/07/20 12:43
 */
@Service
public class UserService extends BaseService<User, Integer> {
    // 在Service层中注入Dao层，这里的Dao层是xxxMapper，
    @Resource
    private UserMapper userMapper;

    /**
     * 用户登录：
     * --1.参数判断，判断用户姓名、用户密码非空
     * ----如果参数为空，抛出异常（异常被控制层捕获并处理）
     * --2.调用数据访问层，通过用户名查询用户记录，返回用户对象
     * --3.判断用户对象是否为空
     * ----如果对象为空，抛出异常（异常被控制层捕获并处理）
     * --4.判断密码是否正确，比较客户端传递的用户密码与数据库中查询的用户对象中的用户密码
     * ----如果密码不相等，抛出异常（异常被控制层捕获并处理）
     * --5.如果密码正确，登录成功
     *
     * @param userName
     * @param userPwd
     */
    public UserModel userLogin(String userName, String userPwd) {
        // 1.参数判断，判断用户姓名、用户密码非空
        checkLoginParams(userName, userPwd);

        // 2.调用数据访问层，通过用户名查询用户记录，返回用户对象
        User user = userMapper.queryUserByName(userName);

        // 3.判断用户对象是否为空
        AssertUtil.isTrue(user == null, "用户姓名不存在！");

        // 4.判断密码是否正确，比较客户端传递的用户密码与数据库中查询的用户对象中的用户密码
        // 首先需要把用户输入的密码加密后，再与数据库中查询到的密码做比较
        checkUserPwd(userPwd, user.getUserPwd());

        // 5.如果密码正确，登录成功
        // 返回构建的用户对象
        return buildUserInfo(user);
    }

    /**
     * 修改密码：
     * --1.接收四个参数 （用户ID、原始密码、新密码、确认密码）
     * --2.通过用户ID查询用户记录，返回用户对象
     * --3.参数校验
     * ----待更新用户记录是否存在 （用户对象是否为空）
     * ----判断原始密码是否为空
     * ----判断原始密码是否正确（查询的用户对象中的用户密码是否原始密码一致）
     * ----判断新密码是否为空
     * ----判断新密码是否与原始密码一致 （不允许新密码与原始密码一致）
     * ----判断确认密码是否为空
     * ----判断确认密码是否与新密码一致
     * --4.设置用户的新密码
     * ----需要将新密码通过指定算法进行加密（md5加密）
     * --5.执行更新操作，判断受影响的行数
     *
     * @param userId    用户Id
     * @param oldPwd    旧密码
     * @param newPwd    新密码
     * @param repeatPwd 确认密码
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void updatePassWord(Integer userId, String oldPwd, String newPwd, String repeatPwd) {
        // 2.通过用户ID查询用户记录，返回用户对象
        User user = userMapper.selectByPrimaryKey(userId);
        // 判断用户记录是否存在
        AssertUtil.isTrue(user == null, "待更新记录不存在！");

        // 参数校验
        checkPasswordParams(user, oldPwd, newPwd, repeatPwd);

        // 4.设置用户的新密码，因为要保存到数据库中，所以要先加密
        user.setUserPwd(Md5Util.encode(newPwd));

        // 5.执行更新操作，判断受影响的行数
        AssertUtil.isTrue(userMapper.updateByPrimaryKeySelective(user) < 1, "修改密码失败！");
    }

    /**
     * 修改密码的参数校验：
     * --判断原始密码是否为空
     * --判断原始密码是否正确（查询的用户对象中的用户密码是否原始密码一致）
     * --判断新密码是否为空
     * --判断新密码是否与原始密码一致 （不允许新密码与原始密码一致）
     * --判断确认密码是否为空
     * --判断确认密码是否与新密码一致
     *
     * @param user
     * @param oldPwd
     * @param newPwd
     * @param repeatPwd
     */
    private void checkPasswordParams(User user, String oldPwd, String newPwd, String repeatPwd) {
        // 判断原始密码是否为空
        AssertUtil.isTrue(StringUtils.isBlank(oldPwd), "原始密码不能为空！");
        // 判断原始密码是否正确（查询的用户对象中的用户密码是否原始密码一致）用户输入的密码需要加密后才与数据库查询出来的密码做比较，因为数据库中的密码是加密的
        AssertUtil.isTrue(!user.getUserPwd().equals(Md5Util.encode(oldPwd)), "原始密码不正确！"); /// 注意这里的取反
        // 判断新密码是否为空
        AssertUtil.isTrue(StringUtils.isBlank(newPwd), "新密码不能为空！");
        // 判断新密码是否与原始密码一致 （不允许新密码与原始密码一致）
        AssertUtil.isTrue(newPwd.equals(oldPwd), "新密码不能与原始密码相同！");
        // 判断确认密码是否为空
        AssertUtil.isTrue(StringUtils.isBlank(repeatPwd), "确认密码不能为空！");
        // 判断确认密码是否与新密码一致
        AssertUtil.isTrue(!repeatPwd.equals(newPwd), "确认密码与新密码不一致！"); /// 注意这里的取反

    }

    /**
     * 构建需要返回给客户端的用户对象
     *
     * @param user
     */
    private UserModel buildUserInfo(User user) {
        UserModel userModel = new UserModel(); // UserModel用于存放需要返回的User字段

//        userModel.setUserId(user.getId());
        // 设置加密后的用户Id
        userModel.setUserIdStr(UserIDBase64.encoderUserID(user.getId()));
        userModel.setUserName(user.getUserName());
        userModel.setTrueName(user.getTrueName());

        return userModel;
    }

    /**
     * 密码判断：
     * --首先需要把用户输入的密码加密后，再与数据库中查询到的密码做比较
     * --通过工具类Md5Util加密用户输入的密码
     *
     * @param userPwd 用户输入的密码
     * @param pwd     查询到的数据库中的密码
     */
    private void checkUserPwd(String userPwd, String pwd) {
        // 首先需要把用户输入的密码加密，然后再和数据库中查到的密码做比较
        userPwd = Md5Util.encode(userPwd);
        // 判断密码是否相等，不相等时，抛出异常提示信息（异常被控制层捕获并处理）
        AssertUtil.isTrue(!userPwd.equals(pwd), "用户密码不正确！"); // 注意这里的取反
    }

    /**
     * 参数判断校验，看是否为空
     * 使用 AssertUtil 工具类辅助判断
     * 使用导入的坐标依赖commons-lang3提供的判空方法
     *
     * @param userName
     * @param usrPwd
     */
    private void checkLoginParams(String userName, String usrPwd) {
        // 验证用户姓名是否为空
        AssertUtil.isTrue(StringUtils.isBlank(userName), "用户姓名不能为空！");
        // 验证用户密码是否为空
        AssertUtil.isTrue(StringUtils.isBlank(usrPwd), "用户密码不能为空！");
    }

    /**
     * 查询所有的销售人员
     *
     * @return
     */
    public List<Map<String, Object>> queryAllSales() {
        return userMapper.queryAllSales();
    }
}
